import { CharStreams, CommonTokenStream } from 'antlr4ts';
import { CymbolLexer } from './CymbolLexer';
import { CymbolParser, PrimaryContext,VarDeclarationContext } from './CymbolParser';

let input = `
int i = 9;
float j;
int k = i+2;
`;

// Create the lexer and parser
let inputStream = CharStreams.fromString(input);
let lexer = new CymbolLexer(inputStream);
let tokenStream = new CommonTokenStream(lexer);
let parser = new CymbolParser(tokenStream);
// AST
let tree = parser.decl();

// 符号表

// 访问器模式
import { AbstractParseTreeVisitor } from 'antlr4ts/tree/AbstractParseTreeVisitor'
import { CymbolVisitor } from './CymbolVisitor';
import { TerminalNode } from 'antlr4ts/tree/TerminalNode';
import { SymbolTable, VariableSymbol } from '.';

// 使用Vistor模式遍历语法树
class MyVisitor extends AbstractParseTreeVisitor<void> implements CymbolVisitor<void> {
    // 声明符号表
    symTab:SymbolTable;

    constructor(){
        super();
        this.symTab = new SymbolTable();
    }
    protected defaultResult(): void {
        
    }
    visitVarDeclaration(ctx:VarDeclarationContext){
        let line = (ctx.ID() as TerminalNode).symbol.line;
        console.log("line " + line + ':' + "ref " + ctx.type().text)

        let vs = new VariableSymbol(
            ctx.ID().text,
            this.symTab.resolve(ctx.type().text)
        );
        this.symTab.define(vs);

        console.log("line " + line + ':' + "def " + ctx.ID().text)
    }

    visitPrimary(ctx:PrimaryContext){
        console.log("pri");

        if(ctx.ID()){
            let line = (ctx.ID() as TerminalNode).symbol.line;
            console.log("line",line);

            let idText = (ctx.ID() as TerminalNode).text
            let idVarSym = this.symTab.resolve(idText);

            console.log("line " + line + ':' + idText + "ref to " +idVarSym.toString())
        }
    }
}
// const cymbolVisitor = new MyVisitor();
// cymbolVisitor.visit(tree);
// console.log(cymbolVisitor.symTab.toString());

// 监听器模式


import { ParseTreeWalker } from 'antlr4ts/tree/ParseTreeWalker'
import { CymbolListener } from './CymbolListener';
import { ParseTreeListener } from "antlr4ts/tree/ParseTreeListener";

class myListener implements CymbolListener {
    symTab:SymbolTable;

    constructor(){
        this.symTab = new SymbolTable();
    }

    enterVarDeclaration(ctx:VarDeclarationContext){
        let line = (ctx.ID() as TerminalNode).symbol.line;
        console.log("line " + line + ':' + "ref " + ctx.type().text)

        let vs = new VariableSymbol(
            ctx.ID().text,
            this.symTab.resolve(ctx.type().text)
        )
        this.symTab.define(vs);

        console.log("line " + line + ':' + "def " + ctx.ID().text)
    }

    enterPrimary(ctx:PrimaryContext){
        if(ctx.ID()){
            let line = (ctx.ID() as TerminalNode).symbol.line;
            let idText = (ctx.ID() as TerminalNode).text
            let idVarSym = this.symTab.resolve(idText);

            console.log("line " + line + ':' + idText + "ref to " +idVarSym.toString())
        }
    }
}


// Create the listener
const listener = new myListener();
ParseTreeWalker.DEFAULT.walk(listener as ParseTreeListener, tree)
console.log(listener.symTab.toString());